#pragma once
#include "FacadeWrapper.h"
#include "PathsHelper.h"

namespace DigitRecognition {

	using namespace System;
	using namespace System::ComponentModel;
	using namespace System::Collections;
	using namespace System::Windows::Forms;
	using namespace System::Data;
	using namespace System::Drawing;

	/// <summary>
	/// Summary for Form1
	/// </summary>
	public ref class Form1 : public System::Windows::Forms::Form
	{
	public:
		Form1(void)
		{
			InitializeComponent();
			//
			//TODO: Add the constructor code here
			//
			facadeWrapper = gcnew FacadeWrapper;
			RefreshButtonsState();
			isTraningState = false;
		}

	protected:
		/// <summary>
		/// Clean up any resources being used.
		/// </summary>
		~Form1()
		{
			if (components)
			{
				delete components;
			}
		}
	private: System::Windows::Forms::Button^  loadNetwork;
	private: System::Windows::Forms::Button^  loadTraningSet;
	private: System::Windows::Forms::Button^  trainNetwork;
	private: System::Windows::Forms::Button^  loadTestingSet;
	private: System::Windows::Forms::Button^  testNetwork;
	private: System::Windows::Forms::Button^  stop;
	private: System::Windows::Forms::Button^  save;
	private: System::Windows::Forms::Button^  createNewNetwork;
	private: FacadeWrapper^ facadeWrapper;
	private: System::ComponentModel::BackgroundWorker^  backgroundWorker1;
	private: bool isTraningState;
	private: System::Windows::Forms::Timer^  timer1;
	private: System::Windows::Forms::Label^  label1;
	private: System::Windows::Forms::Label^  recognitionRatio;
	private: System::Windows::Forms::Label^  label2;
	private: System::Windows::Forms::Label^  trainingError;
	private: System::Windows::Forms::GroupBox^  groupBox1;
	private: System::Windows::Forms::GroupBox^  groupBox2;
	private: System::Windows::Forms::GroupBox^  groupBox3;
	private: System::ComponentModel::IContainer^  components;
	protected: 

	private:
		/// <summary>
		/// Required designer variable.
		/// </summary>


#pragma region Windows Form Designer generated code
		/// <summary>
		/// Required method for Designer support - do not modify
		/// the contents of this method with the code editor.
		/// </summary>
		void InitializeComponent(void)
		{
			this->components = (gcnew System::ComponentModel::Container());
			this->loadNetwork = (gcnew System::Windows::Forms::Button());
			this->loadTraningSet = (gcnew System::Windows::Forms::Button());
			this->trainNetwork = (gcnew System::Windows::Forms::Button());
			this->loadTestingSet = (gcnew System::Windows::Forms::Button());
			this->testNetwork = (gcnew System::Windows::Forms::Button());
			this->stop = (gcnew System::Windows::Forms::Button());
			this->save = (gcnew System::Windows::Forms::Button());
			this->createNewNetwork = (gcnew System::Windows::Forms::Button());
			this->backgroundWorker1 = (gcnew System::ComponentModel::BackgroundWorker());
			this->timer1 = (gcnew System::Windows::Forms::Timer(this->components));
			this->label1 = (gcnew System::Windows::Forms::Label());
			this->recognitionRatio = (gcnew System::Windows::Forms::Label());
			this->label2 = (gcnew System::Windows::Forms::Label());
			this->trainingError = (gcnew System::Windows::Forms::Label());
			this->groupBox1 = (gcnew System::Windows::Forms::GroupBox());
			this->groupBox2 = (gcnew System::Windows::Forms::GroupBox());
			this->groupBox3 = (gcnew System::Windows::Forms::GroupBox());
			this->groupBox1->SuspendLayout();
			this->groupBox2->SuspendLayout();
			this->groupBox3->SuspendLayout();
			this->SuspendLayout();
			// 
			// loadNetwork
			// 
			this->loadNetwork->Location = System::Drawing::Point(108, 18);
			this->loadNetwork->Name = L"loadNetwork";
			this->loadNetwork->Size = System::Drawing::Size(79, 23);
			this->loadNetwork->TabIndex = 1;
			this->loadNetwork->Text = L"Load";
			this->loadNetwork->UseVisualStyleBackColor = true;
			this->loadNetwork->Click += gcnew System::EventHandler(this, &Form1::loadNetwork_Click);
			// 
			// loadTraningSet
			// 
			this->loadTraningSet->Location = System::Drawing::Point(14, 15);
			this->loadTraningSet->Name = L"loadTraningSet";
			this->loadTraningSet->Size = System::Drawing::Size(79, 23);
			this->loadTraningSet->TabIndex = 0;
			this->loadTraningSet->Text = L"LoadSet";
			this->loadTraningSet->UseVisualStyleBackColor = true;
			this->loadTraningSet->Click += gcnew System::EventHandler(this, &Form1::loadTraningSet_Click);
			// 
			// trainNetwork
			// 
			this->trainNetwork->Location = System::Drawing::Point(14, 44);
			this->trainNetwork->Name = L"trainNetwork";
			this->trainNetwork->Size = System::Drawing::Size(79, 23);
			this->trainNetwork->TabIndex = 2;
			this->trainNetwork->Text = L"Train";
			this->trainNetwork->UseVisualStyleBackColor = true;
			this->trainNetwork->Click += gcnew System::EventHandler(this, &Form1::trainNetwork_Click);
			// 
			// loadTestingSet
			// 
			this->loadTestingSet->Location = System::Drawing::Point(14, 16);
			this->loadTestingSet->Name = L"loadTestingSet";
			this->loadTestingSet->Size = System::Drawing::Size(79, 23);
			this->loadTestingSet->TabIndex = 0;
			this->loadTestingSet->Text = L"LoadSet";
			this->loadTestingSet->UseVisualStyleBackColor = true;
			this->loadTestingSet->Click += gcnew System::EventHandler(this, &Form1::loadTestingSet_Click);
			// 
			// testNetwork
			// 
			this->testNetwork->Location = System::Drawing::Point(14, 45);
			this->testNetwork->Name = L"testNetwork";
			this->testNetwork->Size = System::Drawing::Size(79, 23);
			this->testNetwork->TabIndex = 1;
			this->testNetwork->Text = L"Test";
			this->testNetwork->UseVisualStyleBackColor = true;
			this->testNetwork->Click += gcnew System::EventHandler(this, &Form1::testNetwork_Click);
			// 
			// stop
			// 
			this->stop->Location = System::Drawing::Point(108, 19);
			this->stop->Name = L"stop";
			this->stop->Size = System::Drawing::Size(79, 23);
			this->stop->TabIndex = 1;
			this->stop->Text = L"Stop";
			this->stop->UseVisualStyleBackColor = true;
			this->stop->Click += gcnew System::EventHandler(this, &Form1::stop_Click);
			// 
			// save
			// 
			this->save->Location = System::Drawing::Point(108, 47);
			this->save->Name = L"save";
			this->save->Size = System::Drawing::Size(79, 23);
			this->save->TabIndex = 2;
			this->save->Text = L"Save";
			this->save->UseVisualStyleBackColor = true;
			this->save->Click += gcnew System::EventHandler(this, &Form1::save_Click);
			// 
			// createNewNetwork
			// 
			this->createNewNetwork->Location = System::Drawing::Point(14, 18);
			this->createNewNetwork->Name = L"createNewNetwork";
			this->createNewNetwork->Size = System::Drawing::Size(79, 23);
			this->createNewNetwork->TabIndex = 0;
			this->createNewNetwork->Text = L"CreateNew";
			this->createNewNetwork->UseVisualStyleBackColor = true;
			this->createNewNetwork->Click += gcnew System::EventHandler(this, &Form1::createNewNetwork_Click);
			// 
			// backgroundWorker1
			// 
			this->backgroundWorker1->DoWork += gcnew System::ComponentModel::DoWorkEventHandler(this, &Form1::backgroundWorker1_DoWork);
			this->backgroundWorker1->RunWorkerCompleted += gcnew System::ComponentModel::RunWorkerCompletedEventHandler(this, &Form1::backgroundWorker1_RunWorkerCompleted);
			// 
			// timer1
			// 
			this->timer1->Tick += gcnew System::EventHandler(this, &Form1::timer1_Tick);
			// 
			// label1
			// 
			this->label1->AutoSize = true;
			this->label1->Location = System::Drawing::Point(105, 50);
			this->label1->Name = L"label1";
			this->label1->Size = System::Drawing::Size(92, 13);
			this->label1->TabIndex = 8;
			this->label1->Text = L"RecognitionRatio:";
			// 
			// recognitionRatio
			// 
			this->recognitionRatio->AutoSize = true;
			this->recognitionRatio->Location = System::Drawing::Point(203, 50);
			this->recognitionRatio->Name = L"recognitionRatio";
			this->recognitionRatio->Size = System::Drawing::Size(21, 13);
			this->recognitionRatio->TabIndex = 9;
			this->recognitionRatio->Text = L"0%";
			// 
			// label2
			// 
			this->label2->AutoSize = true;
			this->label2->Location = System::Drawing::Point(105, 49);
			this->label2->Name = L"label2";
			this->label2->Size = System::Drawing::Size(70, 13);
			this->label2->TabIndex = 10;
			this->label2->Text = L"TrainingError:";
			// 
			// trainingError
			// 
			this->trainingError->AutoSize = true;
			this->trainingError->Location = System::Drawing::Point(175, 49);
			this->trainingError->Name = L"trainingError";
			this->trainingError->Size = System::Drawing::Size(22, 13);
			this->trainingError->TabIndex = 11;
			this->trainingError->Text = L"0.0";
			// 
			// groupBox1
			// 
			this->groupBox1->Controls->Add(this->createNewNetwork);
			this->groupBox1->Controls->Add(this->save);
			this->groupBox1->Controls->Add(this->loadNetwork);
			this->groupBox1->Location = System::Drawing::Point(9, 22);
			this->groupBox1->Name = L"groupBox1";
			this->groupBox1->Size = System::Drawing::Size(294, 83);
			this->groupBox1->TabIndex = 12;
			this->groupBox1->TabStop = false;
			this->groupBox1->Text = L"Neural Network";
			// 
			// groupBox2
			// 
			this->groupBox2->Controls->Add(this->trainingError);
			this->groupBox2->Controls->Add(this->label2);
			this->groupBox2->Controls->Add(this->stop);
			this->groupBox2->Controls->Add(this->trainNetwork);
			this->groupBox2->Controls->Add(this->loadTraningSet);
			this->groupBox2->Location = System::Drawing::Point(9, 125);
			this->groupBox2->Name = L"groupBox2";
			this->groupBox2->Size = System::Drawing::Size(293, 83);
			this->groupBox2->TabIndex = 13;
			this->groupBox2->TabStop = false;
			this->groupBox2->Text = L"Network Training";
			// 
			// groupBox3
			// 
			this->groupBox3->Controls->Add(this->recognitionRatio);
			this->groupBox3->Controls->Add(this->label1);
			this->groupBox3->Controls->Add(this->testNetwork);
			this->groupBox3->Controls->Add(this->loadTestingSet);
			this->groupBox3->Location = System::Drawing::Point(9, 227);
			this->groupBox3->Name = L"groupBox3";
			this->groupBox3->Size = System::Drawing::Size(292, 81);
			this->groupBox3->TabIndex = 14;
			this->groupBox3->TabStop = false;
			this->groupBox3->Text = L"Network Testing";
			// 
			// Form1
			// 
			this->AutoScaleDimensions = System::Drawing::SizeF(6, 13);
			this->AutoScaleMode = System::Windows::Forms::AutoScaleMode::Font;
			this->ClientSize = System::Drawing::Size(323, 320);
			this->Controls->Add(this->groupBox3);
			this->Controls->Add(this->groupBox2);
			this->Controls->Add(this->groupBox1);
			this->Name = L"Form1";
			this->Text = L"DigitRecognition";
			this->groupBox1->ResumeLayout(false);
			this->groupBox2->ResumeLayout(false);
			this->groupBox2->PerformLayout();
			this->groupBox3->ResumeLayout(false);
			this->groupBox3->PerformLayout();
			this->ResumeLayout(false);

		}
#pragma endregion
	private: System::Void DisableButtons()
			 {
				 createNewNetwork->Enabled = false;
				 loadNetwork->Enabled = false;

				 loadTraningSet->Enabled = false;
				 loadTestingSet->Enabled = false;

				 trainNetwork->Enabled = false;
				 testNetwork->Enabled = false;

				 stop->Enabled = false;
				 save->Enabled = false;
			 }

	private: System::Void RefreshButtonsState()
			 {
				 DisableButtons();
				 if(isTraningState)
				 {
					 stop->Enabled = true;
				 }
				 else
				 {
					 createNewNetwork->Enabled = true;
					 loadNetwork->Enabled = true;
					 if(facadeWrapper->IsNetworkValid())
					 {
						 save->Enabled = true;
						 loadTraningSet->Enabled = true;
						 loadTestingSet->Enabled = true;

						 if(facadeWrapper->IsTrainSetValid())
							 trainNetwork->Enabled = true;

						 if(facadeWrapper->IsTestSetValid())
							 testNetwork->Enabled = true;
					 }
				 }
			 }
	private: System::Void loadTraningSet_Click(System::Object^  /*sender*/, System::EventArgs^  /*e*/) {
				 Cursor->Current = Cursors::WaitCursor;
				 pin_ptr<const wchar_t> directory = PtrToStringChars( PathsHelper::GetMnistDatabaseDirectory() );
				 facadeWrapper->LoadTraingSet(directory);
				 RefreshButtonsState();
				 Cursor->Current = Cursors::Default; 
			 }

	private: System::Void createNewNetwork_Click(System::Object^  /*sender*/, System::EventArgs^  /*e*/) {
				 Cursor->Current = Cursors::WaitCursor;
				 facadeWrapper->CreateNewNetwork();
				 RefreshButtonsState();
				 Cursor->Current = Cursors::Default; 
			 }
	private: System::Void trainNetwork_Click(System::Object^  /*sender*/, System::EventArgs^  /*e*/) {
				 Cursor->Current = Cursors::WaitCursor;
				 backgroundWorker1->RunWorkerAsync();
				 isTraningState = true;
				 RefreshButtonsState();
				 this->timer1->Start();
				 Cursor->Current = Cursors::Default; 
			 }
	private: System::Void backgroundWorker1_DoWork(System::Object^  /*sender*/, System::ComponentModel::DoWorkEventArgs^  /*e*/) {
				 Cursor->Current = Cursors::WaitCursor;
				 facadeWrapper->Train();
				 RefreshButtonsState();
				 Cursor->Current = Cursors::Default; 
			 }
	private: System::Void stop_Click(System::Object^  /*sender*/, System::EventArgs^  /*e*/) {
				 Cursor->Current = Cursors::WaitCursor;
				 this->timer1->Stop();
				 facadeWrapper->StopTraining();
				 while(backgroundWorker1->IsBusy)
					 Application::DoEvents();

				 isTraningState = false;
				 RefreshButtonsState();
				 Cursor->Current = Cursors::Default; 
			 }
	private: System::Void save_Click(System::Object^  /*sender*/, System::EventArgs^  /*e*/) {
				 SaveFileDialog^ saveFileDialog1 = gcnew SaveFileDialog;

				 saveFileDialog1->InitialDirectory = PathsHelper::GetMyDocumentDirectory();
				 saveFileDialog1->Filter = "xml files (*.xml)|*.xml|All files (*.*)|*.*";
				 saveFileDialog1->FilterIndex = 1;
				 saveFileDialog1->RestoreDirectory = true;
				 saveFileDialog1->FileName = "Network";

				 if ( saveFileDialog1->ShowDialog() == System::Windows::Forms::DialogResult::OK )
				 {
					 pin_ptr<const wchar_t> fileName = PtrToStringChars( saveFileDialog1->FileName );
					 Cursor->Current = Cursors::WaitCursor;
					 facadeWrapper->SaveNetwork(fileName);
					 RefreshButtonsState();
					 Cursor->Current = Cursors::Default; 
				 }
			 }
	private: System::Void loadNetwork_Click(System::Object^  /*sender*/, System::EventArgs^  /*e*/) {
				 OpenFileDialog^ openFileDialog1 = gcnew OpenFileDialog;

				 openFileDialog1->InitialDirectory = PathsHelper::GetSampleNetworksDirectory();
				 openFileDialog1->Filter = "xml files (*.xml)|*.xml|All files (*.*)|*.*";
				 openFileDialog1->FilterIndex = 1;
				 openFileDialog1->RestoreDirectory = true;

				 if ( openFileDialog1->ShowDialog() == System::Windows::Forms::DialogResult::OK )
				 {
					 pin_ptr<const wchar_t> fileName = PtrToStringChars( openFileDialog1->FileName );
					 Cursor->Current = Cursors::WaitCursor;
					 facadeWrapper->LoadNetwork(fileName);
					 RefreshButtonsState();
					 Cursor->Current = Cursors::Default; 
				 }
			 }
	private: System::Void loadTestingSet_Click(System::Object^  /*sender*/, System::EventArgs^  /*e*/) {
				 Cursor->Current = Cursors::WaitCursor;
				 pin_ptr<const wchar_t> directory = PtrToStringChars( PathsHelper::GetMnistDatabaseDirectory() );
				 facadeWrapper->LoadTestSet(directory);
				 RefreshButtonsState();
				 Cursor->Current = Cursors::Default; 
			 }
	private: System::Void testNetwork_Click(System::Object^  /*sender*/, System::EventArgs^  /*e*/) {
				 Cursor->Current = Cursors::WaitCursor;
				 double recognitionRatio = facadeWrapper->TestNetwork();
				 this->recognitionRatio->Text = System::Convert::ToString(recognitionRatio) + L"%";
				 RefreshButtonsState();
				 Cursor->Current = Cursors::Default; 
			 }
	private: System::Void timer1_Tick(System::Object^  /*sender*/, System::EventArgs^  /*e*/) {
				 double trainError = facadeWrapper->GetTrainError();
				 this->trainingError->Text = System::Convert::ToString(trainError );
			 }
	private: System::Void backgroundWorker1_RunWorkerCompleted(System::Object^  /*sender*/, System::ComponentModel::RunWorkerCompletedEventArgs^  /*e*/) {
				 this->timer1->Stop();
				 isTraningState = false;
				 this->trainingError->Text = "0.0";
				 RefreshButtonsState();
			 }
	};
}

